package com.cardone.api.util;

import com.cardone.api.support.ExecutionPackageServiceSupport;
import com.cardone.api.support.GetWebPackageServiceSupport;
import com.cardone.api.support.WebPackageServiceSupport;
import com.cardone.common.Characters;
import com.cardone.common.cache.util.CacheUtils;
import com.cardone.common.util.MapperUtils;
import com.cardone.common.util.ReturnDataUtils;
import com.cardone.context.CodeException;
import com.cardone.context.ContextHolder;
import com.cardone.security.token.util.TokenUtils;
import com.cardone.validator.Validator;
import com.cardone.validator.ValidatorRuleTreeConfig;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * Created by Administrator on 2015/4/30.
 */
@Slf4j
public class ApiUtils {
    /**
     * api数据位置
     */
    @Setter
    @Getter
    private static Resource apiLocation;

    /**
     * 数据位置
     */
    @Setter
    @Getter
    private static Resource dataLocation;

    public static Object apiForVersion(final HttpServletRequest request, String servletPath, String requestMethod) throws IOException {
        Map<String, Object> parameterMap = com.cardone.common.util.WebUtils.getParameterMap(request);

        String beanId = FilenameUtils.removeExtension(servletPath) + Characters.dot.stringValue();

        beanId += StringUtils.lowerCase(StringUtils.defaultIfBlank(requestMethod, RequestMethod.GET.name())) + Characters.dot.stringValue() + "json";

        WebPackageServiceSupport webPackageServiceSupport;

        if (log.isDebugEnabled()) {
            webPackageServiceSupport = ContextHolder.getBean(GetWebPackageServiceSupport.class).execution(beanId);
        } else {
            webPackageServiceSupport = CacheUtils.get(ApiUtils.class.getName(), beanId, key -> ContextHolder.getBean(GetWebPackageServiceSupport.class).execution((String) key));
        }

        if (webPackageServiceSupport == null) {
            return apiForVersionDebug(beanId);
        }

        validatorApi(request, parameterMap, webPackageServiceSupport, servletPath);

        return ContextHolder.getBean(ExecutionPackageServiceSupport.class).execution(beanId, parameterMap);
    }

    public static void validatorApi(HttpServletRequest request, Map<String, Object> parameterMap, WebPackageServiceSupport webPackageServiceSupport, String servletPath) {
        if (!CollectionUtils.isEmpty(webPackageServiceSupport.getValidatorRuleTreeConfigList())) {
            Validator validator = com.cardone.context.ContextHolder.getBean(Validator.class);

            for (ValidatorRuleTreeConfig validatorRuleTreeConfig : webPackageServiceSupport.getValidatorRuleTreeConfigList()) {
                validator.validateThrowException(parameterMap.get(validatorRuleTreeConfig.getName()), validatorRuleTreeConfig);
            }
        }

        if (!(BooleanUtils.isTrue(webPackageServiceSupport.getValidatorToken()) || BooleanUtils.isTrue(webPackageServiceSupport.getValidatorTokenUrl()))) {
            return;
        }

        String clientId = TokenUtils.getClientId(request, parameterMap);

        String sessionId = com.cardone.common.util.WebUtils.getSessionId();

        if (StringUtils.isBlank(clientId)) {
            clientId = sessionId;
        }

        String tokenKey = TokenUtils.getTokenKey(request, parameterMap);

        if (BooleanUtils.isTrue(webPackageServiceSupport.getValidatorToken())) {
            TokenUtils.validate(clientId, tokenKey);
        }

        if (BooleanUtils.isTrue(webPackageServiceSupport.getValidatorTokenUrl())) {
            String url = servletPath;

            TokenUtils.validateUrl(clientId, tokenKey, url);
        }

        parameterMap.put(TokenUtils.getClientIdParamName(), clientId);

        CacheUtils.put(sessionId, TokenUtils.getClientIdParamName(), clientId);

        if (StringUtils.isNotBlank(tokenKey)) {
            if (!parameterMap.containsKey(TokenUtils.getTokenParamName())) {
                parameterMap.put(TokenUtils.getTokenParamName(), tokenKey);
            }

            CacheUtils.put(sessionId, TokenUtils.getTokenParamName(), tokenKey);

            if (!StringUtils.equals(clientId, sessionId)) {
                CacheUtils.put(clientId, TokenUtils.getTokenParamName(), tokenKey);
            }
        }
    }

    private static String apiForVersionDebug(String beanId) throws IOException {
        if (!log.isDebugEnabled()) {
            return MapperUtils.toJson(ReturnDataUtils.newMap(null));
        }

        if (ApiUtils.dataLocation == null) {
            throw new CodeException("1000404");
        }

        final File jsonFile = getJsonFile(beanId);

        if ((jsonFile == null) || !jsonFile.exists()) {
            throw new CodeException("没有对应的本地数据， " + jsonFile.getAbsolutePath()).setCode("404");
        }

        final String jsonString = FileUtils.readFileToString(jsonFile, Charsets.UTF_8);

        if (StringUtils.isBlank(jsonString)) {
            return MapperUtils.toJson(ReturnDataUtils.newMap(null));
        }

        return jsonString;
    }

    private static File getJsonFile(String beanId) throws IOException {
        String filename = ApiUtils.apiLocation.getFile().getAbsolutePath() + File.separator + beanId;

        return FileUtils.getFile(filename);
    }
}
